#include <anet/util.h>
#include <anet/anet.h>
#include <anet/ae.h>

#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

#include "packet.h"

int hero_join_in  = 0;
int boss_join_in  = 0;
int sword_join_in = 0;

void Handle(int fd, Packet* packet) {
  printf("FD: %d, magic: %d, id: %d, command: %d, length: %d, game: %d\n", fd, packet->magic, packet->id, packet->command, packet->length, *(int*)packet->data);
  char* ptr = packet->data;
  char* end = packet->data + packet->length;

  while (ptr < end) {

  }

}

void* read_th(void* argv) {
  char* b = (char *)malloc(2048);
  while (1) {
    int fd = (int)(intptr_t)argv;
    int offset = 0;
    while (1) {
      int len = read(fd, b + offset, 2048 - offset);
      if (len < 0) {
        if (errno == EAGAIN || errno == EINTR) continue;
        printf("fuck %d read\n", fd);
        anetClose(fd);
        return NULL;
      } else if (len == 0) {
        printf("fd %d remote close connection\n", fd);
        anetClose(fd);
        return NULL;
      }
      offset += len;
      while (offset >= sizeof(Packet)) {
        Packet* packet = (Packet *)b;
        printf("packet %zu\n", sizeof(Packet));
        if (offset >= sizeof(Packet) + packet->length) {
          Handle(fd, packet);
          int newlen = offset - (sizeof(Packet) + packet->length);
          memmove(b, b + sizeof(Packet) + packet->length, newlen);
          offset = newlen; 
        } else {
          break;
        }
      }
    }
  }
  free(b);
  return NULL;
}

int leave(int fd) {
  struct Packet* packet = (struct Packet *)malloc(sizeof(Packet));
  packet->magic   = MAGIC;
  packet->id      = 20;
  packet->command = 0x03;
  packet->length  = 0;

  int offset = 0;
  while (1) {
    int len = write(fd, packet + offset, sizeof(Packet) - offset);
    if (len < 0) {
      if (errno == EAGAIN || errno == EINTR) continue;
      printf("fuck %d read\n", fd);
      anetClose(fd);
      return -1;
    } else if (len == 0) {
      printf("fd %d remote close connection\n", fd);
      anetClose(fd);
      return -1;
    }
    offset += len;
    if (offset == sizeof(Packet)) {
      break;
    }
  }
  return 0;
}

int joinin(int fd) {
  struct Packet* packet = (struct Packet *)malloc(sizeof(Packet));
  packet->magic   = MAGIC;
  packet->id      = 20;
  packet->command = 0x02;
  packet->length  = 0;

  int offset = 0;
  while (1) {
    int len = write(fd, packet + offset, sizeof(Packet) - offset);
    if (len < 0) {
      if (errno == EAGAIN || errno == EINTR) continue;
      printf("fuck %d read\n", fd);
      anetClose(fd);
      return -1;
    } else if (len == 0) {
      printf("fd %d remote close connection\n", fd);
      anetClose(fd);
      return -1;
    }
    offset += len;
    if (offset == sizeof(Packet)) {
      break;
    }
  }
  return 0;
}

int ack(int fd, int status) {
  struct Packet* packet = (struct Packet *)malloc(sizeof(Packet) + sizeof(int));
  packet->magic   = MAGIC;
  packet->id      = 20;
  packet->command = 0x04;
  packet->length  = 4;
  *(int *)packet->data = status;

  int offset = 0;
  while (1) {
    int len = write(fd, packet + offset, sizeof(Packet) + sizeof(int) - offset);
    if (len < 0) {
      if (errno == EAGAIN || errno == EINTR) continue;
      printf("fuck %d read\n", fd);
      anetClose(fd);
      return -1;
    } else if (len == 0) {
      printf("fd %d remote close connection\n", fd);
      anetClose(fd);
      return -1;
    }
    offset += len;
    if (offset == sizeof(Packet) + sizeof(int)) {
      break;
    }
  }
  return 0;
}

int test(pthread_t* th, int id) {

  int fd = anetTcpNonBlockConnect(NULL, "121.43.109.77", 12345);
  pthread_create(th, NULL, read_th, (void*)(intptr_t)fd);

  joinin(fd);

  return fd;
}

int main() {
  pthread_t th[3];
  int hero = test(th, 10);
  sleep(1);
  int boss = test(th + 1, 11);
  sleep(1);
  int sword = test(th + 2, 12);

  sleep(2);
  printf("=========ACK==========\n");

  ack(hero, 2);
  ack(boss, 2);
  ack(sword, 1);

  sleep(2);
  printf("==========LEAVE=========\n");

  leave(hero);
  leave(boss);
  leave(sword);

  sleep(2);
  printf("========RE-JOININ===========\n");

  joinin(hero);
  sleep(1);
  joinin(boss);
  sleep(1);
  joinin(sword);

  sleep(2);
  printf("=========RE-ACK==========\n");

  ack(hero, 2);
  ack(boss, 2);
  ack(sword, 1);

  sleep(2);
  printf("==========RE-LEAVE=========\n");

  leave(hero);
  leave(boss);
  leave(sword);

  sleep(2);
  printf("========RE-JOININ===========\n");

  joinin(hero);
  sleep(1);
  joinin(boss);
  sleep(1);
  joinin(sword);

  sleep(2);
  printf("=========RE-ACK==========\n");

  int i;
  for (i = 0; i < 20; i++) {
    ack(hero, 2);
    ack(boss, 2);
    ack(sword, 1);
    sleep(1);
  }

  pthread_join(th[0], NULL);
  pthread_join(th[1], NULL);
  pthread_join(th[2], NULL);

  return 0;
}
